<template>
    <div class="wh-100% flex gap-16px overflow-scroll">
        <div class="w-40%">
            <div
                class="w-full flex justify-between items-center"
                style="border-bottom: solid 1px #e5e5e5"
            >
                <span class="font-bold font-size-20px box-border p-10px">
                    预约记录
                </span>
                <n-button-group>
                    <n-tooltip placement="bottom" trigger="hover">
                        <template #trigger>
                            <n-button
                                :focusable="false"
                                @click="showExpiredOrders = true"
                            >
                                <n-icon :component="CashOutline" />
                            </n-button>
                        </template>
                        未成功订单
                    </n-tooltip>
                    <n-button
                        :focusable="false"
                        @click="handleRefreshReservation"
                    >
                        <n-icon :component="Reload" />
                    </n-button>
                </n-button-group>
            </div>
            <n-spin v-if="reservations.length === 0" :show="loading">
                <div class="h-300px flex-center">
                    <n-result
                        status="418"
                        title="暂无预约记录"
                        description="一切尽在不言中"
                    >
                        <template #footer>
                            <n-button
                                :focusable="false"
                                @click="router.push('/layout/reserve')"
                            >
                                go and see
                            </n-button>
                        </template>
                    </n-result>
                </div>
            </n-spin>
            <n-infinite-scroll
                v-else
                @load="handleLoad"
                :distance="50"
                class="max-h-500px"
            >
                <n-collapse
                    v-for="item in reservations"
                    :key="item.id"
                    class="rounded-4px box-border p-16px bg-#fff shadow mt-16px"
                >
                    <n-collapse-item
                        :title="`编号-${item.id}`"
                        @click="getMeetingRoom(item.roomId!)"
                    >
                        <template #header-extra>
                            {{ new Date(item.createdTime!).toLocaleString() }}
                            <n-tag
                                size="small"
                                class="ml-10px"
                                :type="statusMap[item.status].type"
                            >
                                {{ statusMap[item.status].label }}
                            </n-tag>
                        </template>
                        <n-grid cols="400:1 500:2" :x-gap="10">
                            <n-gi>
                                <n-list hoverable>
                                    <n-list-item>
                                        <n-thing
                                            title="创建时间"
                                            :title-extra="new Date(item.createdTime!).toLocaleString()"
                                        />
                                    </n-list-item>
                                    <n-list-item
                                        class="cursor-pointer order-id"
                                        @click="handleShowRoom(item)"
                                    >
                                        <n-thing title="预定会议室">
                                            <template #header-extra>
                                                <div
                                                    class="h-full flex items-center"
                                                >
                                                    {{
                                                        meetingRooms.get(
                                                            item.roomId!
                                                        )?.name || "未知"
                                                    }}
                                                    <n-icon
                                                        class="hidden ml-10px show-order-arrow"
                                                        :component="ArrowRedo"
                                                    />
                                                </div>
                                            </template>
                                        </n-thing>
                                    </n-list-item>
                                </n-list>
                            </n-gi>
                            <n-gi>
                                <n-list hoverable>
                                    <n-list-item>
                                        <n-thing
                                            title="处理时间"
                                            :title-extra="item.processedTime? new Date(item.processedTime!).toLocaleString(): '未处理'"
                                        />
                                    </n-list-item>
                                    <n-list-item
                                        class="cursor-pointer order-id"
                                        @click="handleShowOrder(item)"
                                    >
                                        <n-thing title="订单号">
                                            <template #header-extra>
                                                <div
                                                    class="h-full flex items-center"
                                                >
                                                    {{ item.orderId }}
                                                    <n-icon
                                                        class="hidden ml-10px show-order-arrow"
                                                        :component="ArrowRedo"
                                                    />
                                                </div>
                                            </template>
                                        </n-thing>
                                    </n-list-item>
                                </n-list>
                            </n-gi>
                        </n-grid>
                    </n-collapse-item>
                </n-collapse>
                <div v-if="loading" class="w-full text-center box-border p-8px">
                    加载中...
                </div>
                <div v-if="noMore" class="w-full text-center box-border p-8px">
                    没有更多了
                </div>
            </n-infinite-scroll>
        </div>
        <!-- 展示Order和Requirement -->
        <div
            class="w-60%"
            :style="
                !currentOrder && !currentRoom
                    ? 'opacity: 0; pointer-event: none'
                    : ''
            "
        >
            <div
                class="w-full flex justify-end"
                style="border-bottom: solid 1px #e5e5e5"
            >
                <span class="font-bold font-size-20px box-border p-10px">
                    预约详情
                </span>
            </div>
            <n-spin v-if="currentOrder || currentRoom" :show="loadingOrder">
                <ReservationDetail
                    :room="currentRoom"
                    :order="currentOrder"
                    :model="detailModel"
                    @contextmenu="handleContextMenu"
                />
            </n-spin>
        </div>
        <n-dropdown
            placement="bottom-start"
            trigger="manual"
            :x="xPos"
            :y="yPos"
            :options="dropdownOptions"
            :show="showDropdown"
            @clickoutside="showDropdown = false"
            @select="handleDropdownSelect"
        >
        </n-dropdown>
        <n-modal v-model:show="showExpiredOrders" :auto-focus="false">
            <n-card
                class="w-500px h-600px overflow-scroll"
                content-class="flex select-none"
            >
                <template #header>
                    <div class="w-full flex justify-between">
                        <span>未成功订单</span>
                        <n-button-group>
                            <n-button
                                secondary
                                size="small"
                                :focusable="false"
                                @click="getExpiredOrders_"
                            >
                                <n-icon :component="Reload" :size="18" />
                            </n-button>
                            <n-button
                                secondary
                                type="error"
                                size="small"
                                :focusable="false"
                                :disabled="expiredOrders.length === 0"
                                @click="handleDeleteExpiredOrders"
                            >
                                <n-icon :component="Trash" :size="18" />
                            </n-button>
                        </n-button-group>
                    </div>
                </template>
                <div
                    v-if="expiredOrders.length === 0"
                    class="wh-100% flex-center"
                >
                    <n-empty description="这里空空如也" size="large" />
                </div>
                <n-collapse
                    v-else
                    accordion
                    default-expanded-names="1"
                    arrow-placement="right"
                >
                    <n-collapse-item
                        v-for="(item, index) in expiredOrders"
                        :key="item.id"
                        :name="`${index + 1}`"
                        :title="`订单号-${item.id}`"
                    >
                        <n-descriptions bordered :column="2">
                            <n-descriptions-item label="预约日期">
                                {{
                                    new Date(
                                        item.requirement.reserveDate!
                                    ).toLocaleString()
                                }}
                            </n-descriptions-item>
                            <n-descriptions-item label="预约时间">
                                {{
                                    `${item.requirement.startTime}:00-${item.requirement.endTime}:00`
                                }}
                            </n-descriptions-item>
                            <n-descriptions-item label="订单金额">
                                {{ item.amount }}
                            </n-descriptions-item>
                            <n-descriptions-item label="创建时间">
                                {{
                                    new Date(item.createdTime).toLocaleString()
                                }}
                            </n-descriptions-item>
                        </n-descriptions>
                    </n-collapse-item>
                </n-collapse>
            </n-card>
        </n-modal>
        <n-modal v-model:show="showCancelModal">
            <n-card class="w-500px select-none">
                <template #header> 取消预约 </template>
                <n-list hoverable>
                    <n-list-item>
                        <n-thing
                            title="预约单号"
                            :title-extra="currentReservation!.id"
                        />
                    </n-list-item>
                    <n-list-item>
                        <n-thing title="退款倍率">
                            <template #header-extra>
                                <div class="h-30px flex items-center gap-4px">
                                    <span>
                                        {{
                                            refundPercentage === 1
                                                ? "100%"
                                                : refundPercentage === 0.75
                                                ? "75%"
                                                : "25%"
                                        }}
                                    </span>
                                    <n-popover trigger="hover">
                                        <template #trigger>
                                            <n-icon
                                                :component="AlertCircleOutline"
                                                :size="20"
                                            />
                                        </template>
                                        申请时间距离预约时间提前72小时退全款<br />提前48小时退75%，提前24小时退25%
                                    </n-popover>
                                </div>
                            </template>
                        </n-thing>
                    </n-list-item>
                    <n-list-item>
                        <n-thing
                            title="退款金额"
                            :title-extra="`${refundAmount}￥`"
                        />
                    </n-list-item>
                    <n-list-item>
                        <n-thing title="取消原因">
                            <template #header-extra>
                                <n-input
                                    v-model:value="cancellationReason"
                                    :maxlength="50"
                                    clearable
                                    show-count
                                    type="textarea"
                                    placeholder="请输入取消原因"
                                />
                            </template>
                        </n-thing>
                    </n-list-item>
                </n-list>
                <template #footer>
                    <div class="w-full flex justify-end gap-10px">
                        <n-button
                            class="w-80px"
                            @click="showCancelModal = false"
                        >
                            放弃
                        </n-button>
                        <n-button
                            class="w-80px"
                            type="primary"
                            :disabled="cancellationReason === ''"
                            @click="handleCancelReservation"
                        >
                            提交
                        </n-button>
                    </div>
                </template>
            </n-card>
        </n-modal>
    </div>
</template>

<script lang="ts" setup>
import { h, ref, reactive, onMounted } from "vue";
import type { Component, VNodeChild } from "vue";
import { getStore } from "@/store";
import { useRouter } from "vue-router";
import { calcTimeAway } from "@/utils/time";

import { NIcon, NInput } from "naive-ui";
import type { DropdownOption } from "naive-ui";
import {
    Trash,
    Reload,
    ArrowUndo,
    ArrowRedo,
    CashOutline,
    AlertCircleOutline,
} from "@vicons/ionicons5";

import type {
    Order,
    Reservation,
    Cancellation,
} from "@/service/api/types/reservation";
import type { MeetingRoom } from "@/service/api/types/room";

import {
    getReservationsByCustomerId,
    cancelReservation,
} from "@/service/api/modules/reservation";
import {
    getOrderById,
    getExpiredOrders,
    deleteExpiredOrders,
} from "@/service/api/modules/order";
import { getMeetingRoomById } from "@/service/api/modules/room";
import ReservationDetail from "../components/reservation-detail/index.vue";

const router = useRouter();
const userStore = getStore("user");

// reservation 加载中
const loading = ref(false);
// order 加载中
const loadingOrder = ref(false);
// reservation 加载完毕
const noMore = ref(false);

// 缓存的 reservation、 order和 meetingRoom
const reservations = ref<Reservation[]>([]);
const currentReservation = ref<Reservation | null>(null);

const orders: Map<string, Order> = new Map();
const currentOrder = ref<Order | null>(null);

const meetingRooms = ref<Map<string, MeetingRoom>>(new Map());
const currentRoom = ref<MeetingRoom | null>(null);

const showExpiredOrders = ref(false);
const expiredOrders = ref<Order[]>([]);

// 取消预订模态框
const showCancelModal = ref(false);
// 取消预定原因
const cancellationReason = ref("");
const detailModel = ref<"order" | "room">("order");

// 退款金额
const refundAmount = ref(0);
const refundPercentage = ref(0);

const pagination = reactive({
    page: 1,
    size: 10,
});

const showDropdown = ref(false);
const xPos = ref(0);
const yPos = ref(0);

// 状态映射 -> 标签类型和标签文字
const statusMap: { [key: string]: { type: string; label: string } } = {
    verifying: { type: "info", label: "待审核" },
    rejected: { type: "error", label: "被拒绝" },
    confirmed: { type: "success", label: "待使用" },
    refunded: { type: "warning", label: "已退款" },
    completed: { type: "", label: "已完成" },
    refund_verifying: { type: "info", label: "退款中" },
};

const renderIcon = (icon: Component) => {
    return () => {
        return h(
            NIcon,
            { size: 18 },
            {
                default: () => h(icon),
            }
        );
    };
};

const dropdownOptions = reactive<DropdownOption[]>([
    {
        label: "取消预定",
        key: "refund",
        disabled: true,
        icon: renderIcon(ArrowUndo),
    },
]);

onMounted(async () => {
    handleLoad();
    getExpiredOrders_();
});

// 获取未成功订单 -> 只获取订单，没有预约单和会议室信息
const getExpiredOrders_ = async () => {
    try {
        expiredOrders.value = await getExpiredOrders(userStore.getUserInfo.id);
    } catch (err) {
        window.NMessage.error((err as Error).message);
    }
};

// 加载更多预定记录
const handleLoad = async () => {
    if (noMore.value) {
        return;
    }
    loading.value = true;
    try {
        const res = await getReservationsByCustomerId(
            userStore.getUserInfo.id,
            pagination.page++,
            pagination.size
        );
        // 如果获取到的记录条数小于页面条数说明加载完成
        if (res.length < pagination.size) {
            noMore.value = true;
        }
        reservations.value = reservations.value.concat(res);
        loading.value = false;
    } catch (err) {
        window.NMessage.error((err as Error).message);
    }
};

// 获取会议室信息
const getMeetingRoom = async (id: string) => {
    if (meetingRooms.value.has(id)) {
        return;
    }
    try {
        const res = await getMeetingRoomById(id);
        meetingRooms.value.set(id, res);
    } catch (err) {
        window.NMessage.error((err as Error).message);
    }
};

// 刷新预约记录记录
const handleRefreshReservation = () => {
    // 重置状态
    loading.value = true;
    noMore.value = false;
    pagination.page = 1;

    // 重置数据
    reservations.value = [];

    orders.clear();
    currentOrder.value = null;

    meetingRooms.value.clear();
    currentRoom.value = null;
    // 刷新后重新加载
    handleLoad();
};

// 展示订单详情
const handleShowOrder = async (item: Reservation) => {
    detailModel.value = "order";
    currentReservation.value = item;
    // 先从缓存中查找
    if (orders.has(item.orderId)) {
        currentOrder.value = orders.get(item.orderId)!;
        return;
    }
    loadingOrder.value = true;
    // 如果缓存中没有则从服务器获取
    try {
        const res = await getOrderById(item.orderId);
        if (!res) {
            window.NMessage.error("订单不存在");
            return;
        }
        orders.set(item.orderId, res);
        currentOrder.value = res;
    } catch (err) {
        window.NMessage.error((err as Error).message);
    } finally {
        loadingOrder.value = false;
    }
};

// 展示会议室详情
const handleShowRoom = (item: Reservation) => {
    detailModel.value = "room";
    currentReservation.value = item;
    if (meetingRooms.value.has(item.roomId!)) {
        currentRoom.value = meetingRooms.value.get(item.roomId!)!;
        return;
    }
    currentRoom.value = null;
    window.NMessage.error("会议室不存在");
};

// 右键显示下拉菜单
const handleContextMenu = (e: MouseEvent) => {
    e.preventDefault();
    showDropdown.value = true;
    xPos.value = e.clientX;
    yPos.value = e.clientY;
    // 如果订单不是正在预定中的状态则无法退款
    dropdownOptions[0].disabled =
        currentReservation.value!.status === "confirmed" ? false : true;
};

// 点击右键菜单事件
const handleDropdownSelect = (key: string) => {
    showDropdown.value = false;
    if (key === "refund") {
        const hourDiff = calcTimeAway(
            currentOrder.value!.requirement.reserveDate!,
            currentOrder.value!.requirement.startTime!
        );
        if (hourDiff < 24) {
            window.NMessage.error("距预约时间不足24小时，无法取消");
            return;
        }
        refundPercentage.value =
            hourDiff >= 72 ? 1 : hourDiff >= 48 ? 0.75 : 0.25;
        refundAmount.value =
            currentOrder.value!.amount * refundPercentage.value;
        showCancelModal.value = true;
    }
};

// 取消预约
const handleCancelReservation = async () => {
    window.NDialog.warning({
        title: "取消预约",
        content: "是否取消该预约？",
        closable: false,
        positiveText: "确定",
        negativeText: "取消",
        onPositiveClick: async () => {
            try {
                const cancellation: Cancellation = {
                    id: "",
                    customerId: userStore.getUserInfo.id,
                    reservationId: currentReservation.value!.id,
                    cancellationReason: cancellationReason.value,
                    refundAmount: refundAmount.value,
                    refundPercentage: refundPercentage.value,
                    status: "requested",
                    processedTime: 0,
                    createdTime: Date.now(),
                };
                await cancelReservation(cancellation);
                window.NMessage.success("取消成功");
                showCancelModal.value = false;
                handleRefreshReservation();
            } catch (err) {
                window.NMessage.error((err as Error).message);
            } finally {
                cancellationReason.value = "";
            }
        },
    });
};

const handleDeleteExpiredOrders = async () => {
    window.NDialog.warning({
        title: "删除未成功订单",
        content: "是否删除所有未成功订单？",
        closable: false,
        positiveText: "确定",
        negativeText: "取消",
        onPositiveClick: async () => {
            try {
                await deleteExpiredOrders(userStore.getUserInfo.id);
                expiredOrders.value = [];
                showExpiredOrders.value = false;
                window.NMessage.success("删除成功");
            } catch (err) {
                window.NMessage.error((err as Error).message);
            }
        },
    });
};
</script>

<style scoped>
.order-id:hover .show-order-arrow {
    display: block;
}
</style>
